#include "Client.h"
#include "BlockRender.h"
#include "World.h"
#include "Material.h"
#include "Block.h"

BlockRender::BlockRender(Client* cli, Chunk* chu, float side){
	client = cli;
	chunk = chu;
	this->side = side;
	force_mat = NULL;
	block = NULL;
}

void BlockRender::ForceMaterial(Material* m){
	force_mat = m;
}

void BlockRender::SetBlock(Block* b){
	block = b;
}

bool BlockRender::Generate(Block* block, Block* north, Block* south, Block* east, Block* west, Block* up, Block* down, mc_Vertex* verts[6], int** vi, float x, float y, float z, float height){
	int j;
	int v = 0;
	bool force_sides = false;
	Material* material = block->getMaterial();
	b_down = down;
	this->block = block;
	this->mat = material;

	if(material->renderProps.blockType == 2 || material->renderProps.blockType == 3 || material->renderProps.blockType == 4){
		force_sides = true;
	}

	Material* p_north = north ? Material::FindByIdData(north->getId(), north->getData()) : NULL;
	Material* p_south = south ? Material::FindByIdData(south->getId(), south->getData()) : NULL;
	Material* p_east = east ? Material::FindByIdData(east->getId(), east->getData()) : NULL;
	Material* p_west = west ? Material::FindByIdData(west->getId(), west->getData()) : NULL;
	Material* p_up = up ? Material::FindByIdData(up->getId(), up->getData()) : NULL;
	Material* p_down = down ? Material::FindByIdData(down->getId(), down->getData()) : NULL;
	
	if(!p_up){
		p_up = Material::FindById(1);
	}
	if(!p_down){
		p_down = Material::FindById(1);
	}
	if(!p_north){
		p_north = Material::FindById(1);
	}
	if(!p_south){
		p_south = Material::FindById(1);
	}
	if(!p_east){
		p_east = Material::FindById(1);
	}
	if(!p_west){
		p_west = Material::FindById(1);
	}

	bool force_up = !p_up;
	bool force_down = !p_down;
	bool force_north = !p_north;
	bool force_south = !p_south;
	bool force_east = !p_east;
	bool force_west = !p_west;
	if(p_north && p_north->renderProps.blockType == BLOCK_TYPE_STAIRS){
		if((p_north->getData() & 3) == 3 || (p_north->getData() & 2) == 2){
			force_east = true;
		}else{
			force_north = true;
		}
	}
	if(p_south && p_south->renderProps.blockType == BLOCK_TYPE_STAIRS){
		if((p_south->getData() & 3) == 3 || (p_south->getData() & 2) == 2){
			force_west = true;
		}else{
			force_south = true;
		}
	}
	if(p_east && p_east->renderProps.blockType == BLOCK_TYPE_STAIRS){
		if((p_east->getData() & 1) == 1 || (p_east->getData() & 1) == 0){
			force_east = true;
		}else{
			force_north = true;
		}
	}
	if(p_west && p_west->renderProps.blockType == BLOCK_TYPE_STAIRS){
		if((p_west->getData() & 1) == 1 || (p_west->getData() & 1) == 0){
			force_west = true;
		}else{
			force_south = true;
		}
	}
	if(p_north && p_north->getId() == 78 && p_north->getData() < 7){
		force_north = true;
	}
	if(p_south && p_south->getId() == 78 && p_south->getData() < 7){
		force_south = true;
	}
	if(p_east && p_east->getId() == 78 && p_east->getData() < 7){
		force_east = true;
	}
	if(p_west && p_west->getId() == 78 && p_west->getData() < 7){
		force_west = true;
	}
	
	if(material->renderProps.blockType == BLOCK_TYPE_CUBE || material->renderProps.blockType == BLOCK_TYPE_LEAVES || material->renderProps.blockType == BLOCK_TYPE_DOUBLE_SLAB || material->renderProps.blockType == BLOCK_TYPE_SLAB || material->renderProps.blockType == BLOCK_TYPE_WATER){
		bool r_north = force_north || (p_north && (p_north->isSolid() == 0 || p_north->renderProps.blockType == 5) && (p_north->getId() != block->getId() || force_sides));
		bool r_south = force_south || (p_south && (p_south->isSolid() == 0 || p_south->renderProps.blockType == 5) && (p_south->getId() != block->getId() || force_sides));
		bool r_east = force_east || (p_east && (p_east->isSolid() == 0 || p_east->renderProps.blockType == 5) && (p_east->getId() != block->getId() || force_sides));
		bool r_west = force_west || (p_west && (p_west->isSolid() == 0 || p_west->renderProps.blockType == 5) && (p_west->getId() != block->getId() || force_sides));
		bool r_up = force_up || (p_up && (p_up->isSolid() == 0 || p_up->renderProps.blockType == 5) && (p_up->getId() != block->getId() || force_sides));
		bool r_down = force_down || (p_down && (p_down->isSolid() == 0 || p_down->renderProps.blockType == 5) && (p_down->getId() != block->getId() || force_sides));
		if(material->renderProps.blockType == BLOCK_TYPE_SLAB){
			height = 0.5;
		}
		GenerateCube(height, r_north, r_south, r_east, r_west, r_up, r_down, (u8**)verts, vi, x, y, z);
		return true;
	}
	else
	if(material->renderProps.blockType == 2){
		material = new Material(material);
		if((p_north && p_north->getId() == 78) || (p_south && p_south->getId() == 78) || (p_east && p_east->getId() == 78) || (p_west && p_west->getId() == 78)){
			material->setBiomeColored(0);
		}
		GenerateSpriteVolume(height, true, true, true, true, false, false, (u8**)verts, vi, x, y, z);
		delete material;
		return true;
	}else
	if(material->renderProps.blockType == 4){
	//	GenTorch(block, material, height, true, true, true, true, true, true, verts, x, y, z);
	}else
	if(material->renderProps.blockType == 6){
		bool r_north = force_north || (p_north && (p_north->isSolid() == 0 || p_north->renderProps.blockType == 5) && (p_north->getId() != block->getId() || force_sides));
		bool r_south = force_south || (p_south && (p_south->isSolid() == 0 || p_south->renderProps.blockType == 5) && (p_south->getId() != block->getId() || force_sides));
		bool r_east = force_east || (p_east && (p_east->isSolid() == 0 || p_east->renderProps.blockType == 5) && (p_east->getId() != block->getId() || force_sides));
		bool r_west = force_west || (p_west && (p_west->isSolid() == 0 || p_west->renderProps.blockType == 5) && (p_west->getId() != block->getId() || force_sides));
		bool r_up = force_up || (p_up && (p_up->isSolid() == 0 || p_up->renderProps.blockType == 5) && (p_up->getId() != block->getId() || force_sides));
		bool r_down = force_down || (p_down && (p_down->isSolid() == 0 || p_down->renderProps.blockType == 5) && (p_down->getId() != block->getId() || force_sides));
		GenerateStairs(height, r_north, r_south, r_east, r_west, r_up, r_down, (u8**)verts, vi, x, y, z);
		return true;
	}else
	if(material->renderProps.blockType == 8){
		GenerateRail(height, true, true, true, true, true, true, (u8**)verts, vi, x, y, z);
		return true;
	}
	return false;
}

void BlockRender::GenerateCube(float height, bool north, bool south, bool east, bool west, bool up, bool down, u8* verts[6], int** vi, float x, float y, float z){
	int j;
	int biome_color = 0;
	int v0[6];
	v0[0] = (*vi)[0];
	v0[1] = (*vi)[1];
	v0[2] = (*vi)[2];
	v0[3] = (*vi)[3];
	v0[4] = (*vi)[4];
	v0[5] = (*vi)[5];
	
	if(this->force_mat){
		this->mat = this->force_mat;
	}
	float tu = mat->renderProps.u;
	float tv = mat->renderProps.v;
	float tw = mat->renderProps.w;
	float th = mat->renderProps.h;

	if(mat->renderProps.blockType == BLOCK_TYPE_SLAB){
		th *= 0.5;
	}

	if(north){
		float l_tu = tu;
		float l_tv = tv;
		biome_color = mat->isBiomeColored() & 0x000001;
		if(block->getId() == 2){
			FancyGrass(block, &l_tu, &l_tv, &biome_color, -1, 0);
		}
		int light = 255;
		Block* feet = client->getWorld()->FindBlock(chunk->getX() + floor(x) - 1, chunk->getY() + floor(y), floor(z) - 1);
		if(feet && feet->getMaterial() && feet->getMaterial()->isSolid()){
			light = 180;
		}

		MakeVertex(verts[NORTH] + client->options.vertex_size * ((*vi)[NORTH]+0), NORTH, biome_color, light, x, y+side, z+0.0, l_tu, l_tv+th, -1.0, 0.0, 0.0);
		MakeVertex(verts[NORTH] + client->options.vertex_size * ((*vi)[NORTH]+1), NORTH, biome_color, light, x, y, z+0.0, l_tu+tw, l_tv+th, -1.0, 0.0, 0.0);
		MakeVertex(verts[NORTH] + client->options.vertex_size * ((*vi)[NORTH]+2), NORTH, biome_color, 255, x, y, z+height, l_tu+tw, l_tv, -1.0, 0.0, 0.0);
		MakeVertex(verts[NORTH] + client->options.vertex_size * ((*vi)[NORTH]+3), NORTH, biome_color, 255, x, y, z+height, l_tu+tw, l_tv, -1.0, 0.0, 0.0);
		MakeVertex(verts[NORTH] + client->options.vertex_size * ((*vi)[NORTH]+4), NORTH, biome_color, 255, x, y+side, z+height, l_tu, l_tv, -1.0, 0.0, 0.0);
		MakeVertex(verts[NORTH] + client->options.vertex_size * ((*vi)[NORTH]+5), NORTH, biome_color, light, x, y+side, z+0.0, l_tu, l_tv+th, -1.0, 0.0, 0.0);
		(*vi)[NORTH] += 6;
	}

	if(south){
		float l_tu = tu;
		float l_tv = tv;
		biome_color = mat->isBiomeColored() & 0x000010;
		if(block->getId() == 2){
			FancyGrass(block, &l_tu, &l_tv, &biome_color, 1, 0);
		}
		int light = 255;
		Block* feet = client->getWorld()->FindBlock(chunk->getX() + floor(x) + 1, chunk->getY() + floor(y), floor(z) - 1);
		if(feet && feet->getMaterial() && feet->getMaterial()->isSolid()){
			light = 180;
		}

		MakeVertex(verts[SOUTH] + client->options.vertex_size * ((*vi)[SOUTH]+0), SOUTH, biome_color, light, x+side, y+side, z+0.0, l_tu+tw, l_tv+th, 1.0, 0.0, 0.0);
		MakeVertex(verts[SOUTH] + client->options.vertex_size * ((*vi)[SOUTH]+1), SOUTH, biome_color, 255, x+side, y, z+height, l_tu, l_tv, 1.0, 0.0, 0.0);
		MakeVertex(verts[SOUTH] + client->options.vertex_size * ((*vi)[SOUTH]+2), SOUTH, biome_color, light, x+side, y, z+0.0, l_tu, l_tv+th, 1.0, 0.0, 0.0);
		MakeVertex(verts[SOUTH] + client->options.vertex_size * ((*vi)[SOUTH]+3), SOUTH, biome_color, 255, x+side, y, z+height, l_tu, l_tv, 1.0, 0.0, 0.0);
		MakeVertex(verts[SOUTH] + client->options.vertex_size * ((*vi)[SOUTH]+4), SOUTH, biome_color, light, x+side, y+side, z+0.0, l_tu+tw, l_tv+th, 1.0, 0.0, 0.0);
		MakeVertex(verts[SOUTH] + client->options.vertex_size * ((*vi)[SOUTH]+5), SOUTH, biome_color, 255, x+side, y+side, z+height, l_tu+tw, l_tv, 1.0, 0.0, 0.0);
		(*vi)[SOUTH] += 6;
	}
	if(east){
		float l_tu = tu;
		float l_tv = tv;
		biome_color = mat->isBiomeColored() & 0x000100;
		if(block->getId() == 2){
			FancyGrass(block, &l_tu, &l_tv, &biome_color, 0, -1);
		}
		int light = 255;
		Block* feet = client->getWorld()->FindBlock(chunk->getX() + floor(x), chunk->getY() + floor(y) - 1, floor(z) - 1);
		if(feet && feet->getMaterial() && feet->getMaterial()->isSolid()){
			light = 180;
		}

		MakeVertex(verts[EAST] + client->options.vertex_size * ((*vi)[EAST]+0), EAST, biome_color, light, x, y, z+0.0, l_tu, l_tv+th, 0.0, -1.0, 0.0);
		MakeVertex(verts[EAST] + client->options.vertex_size * ((*vi)[EAST]+1), EAST, biome_color, light, x+side, y, z+0.0, l_tu+tw, l_tv+th, 0.0, -1.0, 0.0);
		MakeVertex(verts[EAST] + client->options.vertex_size * ((*vi)[EAST]+2), EAST, biome_color, 255, x+side, y, z+height, l_tu+tw, l_tv, 0.0, -1.0, 0.0);
		MakeVertex(verts[EAST] + client->options.vertex_size * ((*vi)[EAST]+3), EAST, biome_color, 255, x+side, y, z+height, l_tu+tw, l_tv, 0.0, -1.0, 0.0);
		MakeVertex(verts[EAST] + client->options.vertex_size * ((*vi)[EAST]+4), EAST, biome_color, 255, x, y, z+height, l_tu, l_tv, 0.0, -1.0, 0.0);
		MakeVertex(verts[EAST] + client->options.vertex_size * ((*vi)[EAST]+5), EAST, biome_color, light, x, y, z+0.0, l_tu, l_tv+th, 0.0, -1.0, 0.0);
		(*vi)[EAST] += 6;
	}
	if(west){
		float l_tu = tu;
		float l_tv = tv;
		biome_color = mat->isBiomeColored() & 0x001000;
		if(block->getId() == 2){
			FancyGrass(block, &l_tu, &l_tv, &biome_color, 0, 1);
		}
		int light = 255;
		Block* feet = client->getWorld()->FindBlock(chunk->getX() + floor(x), chunk->getY() + floor(y) + 1, floor(z) - 1);
		if(feet && feet->getMaterial() && feet->getMaterial()->isSolid()){
			light = 180;
		}

		MakeVertex(verts[WEST] + client->options.vertex_size * ((*vi)[WEST]+0), WEST, biome_color, light, x+side, y+side, z+0.0, l_tu, l_tv+th, 0.0, 1.0, 0.0);
		MakeVertex(verts[WEST] + client->options.vertex_size * ((*vi)[WEST]+1), WEST, biome_color, light, x, y+side, z+0.0, l_tu+tw, l_tv+th, 0.0, 1.0, 0.0);
		MakeVertex(verts[WEST] + client->options.vertex_size * ((*vi)[WEST]+2), WEST, biome_color, 255, x, y+side, z+height, l_tu+tw, l_tv, 0.0, 1.0, 0.0);
		MakeVertex(verts[WEST] + client->options.vertex_size * ((*vi)[WEST]+3), WEST, biome_color, 255, x, y+side, z+height, l_tu+tw, l_tv, 0.0, 1.0, 0.0);
		MakeVertex(verts[WEST] + client->options.vertex_size * ((*vi)[WEST]+4), WEST, biome_color, 255, x+side, y+side, z+height, l_tu, l_tv, 0.0, 1.0, 0.0);
		MakeVertex(verts[WEST] + client->options.vertex_size * ((*vi)[WEST]+5), WEST, biome_color, light, x+side, y+side, z+0.0, l_tu, l_tv+th, 0.0, 1.0, 0.0);
		(*vi)[WEST] += 6;
	}
	
	if(mat->renderProps.blockType == BLOCK_TYPE_SLAB){
		th *= 2.0;
	}
	Material* mat0 = mat;
	if(mat->renderProps.blockType == BLOCK_TYPE_SLAB || mat->renderProps.blockType == BLOCK_TYPE_DOUBLE_SLAB){
		mat = Material::FindByIdData(mat->getId(), mat->getData() + 16);
	}
	if(!mat){
		mat = mat0;
	}
	if(up){
		float l_tu = mat->renderProps.u;
		float l_tv = mat->renderProps.v;
		biome_color = mat->isBiomeColored() & 0x010000;

		if(block->getId() == 2){
			l_tu = Material::FindByIdData(2, 1)->renderProps.u;
			l_tv = Material::FindByIdData(2, 1)->renderProps.v;
		}
		MakeVertex(verts[UP] + client->options.vertex_size * ((*vi)[UP]+0), UP, biome_color, 255, x, y, z+height, l_tu+tw, l_tv, 0.0, 0.0, 1.0);
		MakeVertex(verts[UP] + client->options.vertex_size * ((*vi)[UP]+1), UP, biome_color, 255, x+side, y, z+height, l_tu+tw, l_tv+th, 0.0, 0.0, 1.0);
		MakeVertex(verts[UP] + client->options.vertex_size * ((*vi)[UP]+2), UP, biome_color, 255, x+side, y+side, z+height, l_tu, l_tv+th, 0.0, 0.0, 1.0);
		MakeVertex(verts[UP] + client->options.vertex_size * ((*vi)[UP]+3), UP, biome_color, 255, x+side, y+side, z+height, l_tu, l_tv+th, 0.0, 0.0, 1.0);
		MakeVertex(verts[UP] + client->options.vertex_size * ((*vi)[UP]+4), UP, biome_color, 255, x, y+side, z+height, l_tu, l_tv, 0.0, 0.0, 1.0);
		MakeVertex(verts[UP] + client->options.vertex_size * ((*vi)[UP]+5), UP, biome_color, 255, x, y, z+height, l_tu+tw, l_tv, 0.0, 0.0, 1.0);
		(*vi)[UP] += 6;
	}
	mat0 = mat;
	if(mat->renderProps.blockType == BLOCK_TYPE_SLAB || mat->renderProps.blockType == BLOCK_TYPE_DOUBLE_SLAB){
		mat = Material::FindByIdData(mat->getId(), mat->getData() + 16);
	}
	if(!mat){
		mat = mat0;
	}
	if(down){
		float l_tu = mat->renderProps.u;
		float l_tv = mat->renderProps.v;
		biome_color = mat->isBiomeColored() & 0x100000;

		if(block->getId() == 2){
			l_tu = Material::FindById(3)->renderProps.u;
			l_tv = Material::FindById(3)->renderProps.v;
		}
		MakeVertex(verts[DOWN] + client->options.vertex_size * ((*vi)[DOWN]+0), DOWN, biome_color, 255, x, y, z+0.0, l_tu+tw, l_tv, 0.0, 0.0, -1.0);
		MakeVertex(verts[DOWN] + client->options.vertex_size * ((*vi)[DOWN]+1), DOWN, biome_color, 255, x, y+side, z+0.0, l_tu+tw, l_tv+th, 0.0, 0.0, -1.0);
		MakeVertex(verts[DOWN] + client->options.vertex_size * ((*vi)[DOWN]+2), DOWN, biome_color, 255, x+side, y+side, z+0.0, l_tu, l_tv+th, 0.0, 0.0, -1.0);
		MakeVertex(verts[DOWN] + client->options.vertex_size * ((*vi)[DOWN]+3), DOWN, biome_color, 255, x+side, y+side, z+0.0, l_tu, l_tv+th, 0.0, 0.0, -1.0);
		MakeVertex(verts[DOWN] + client->options.vertex_size * ((*vi)[DOWN]+4), DOWN, biome_color, 255, x+side, y, z+0.0, l_tu, l_tv, 0.0, 0.0, -1.0);
		MakeVertex(verts[DOWN] + client->options.vertex_size * ((*vi)[DOWN]+5), DOWN, biome_color, 255, x, y, z+0.0, l_tu+tw, l_tv, 0.0, 0.0, -1.0);
		(*vi)[DOWN] += 6;
	}

	if(mat->renderProps.blockType == 3 || mat->renderProps.blockType == 16){
		for(int k=0; k<6; k++){
			for(j=0; j<((*vi)[k]-v0[k]); j++){
				int mode = 0;
				if(mat->renderProps.blockType == 3){
					mode = 2;
					if(b_down && b_down->getMaterial() && b_down->getMaterial()->isSolid()){
						if(client->options.opengl_mode == GL_MODE_FAST && ((mc_Vertex_Fast**)verts)[k][(*vi)[k]-((*vi)[k]-v0[k])+j].z == z){
							mode = 0;
						}else
						if(client->options.opengl_mode == GL_MODE_BASIC && ((mc_Vertex_Basic**)verts)[k][(*vi)[k]-((*vi)[k]-v0[k])+j].z == z){
							mode = 0;
						}else
						if(client->options.opengl_mode == GL_MODE_FULL && ((mc_Vertex**)verts)[k][(*vi)[k]-((*vi)[k]-v0[k])+j].z == z){
							mode = 0;
						}
					}
				}else
				if(mat->renderProps.blockType == 16){
					mode = 9;
				}
				if(client->options.opengl_mode == GL_MODE_FAST){
					// No physic animation
				}else
				if(client->options.opengl_mode == GL_MODE_BASIC){
					((mc_Vertex_Basic**)verts)[k][(*vi)[k]-((*vi)[k]-v0[k])+j].anim_mode += 10.0 * mode;
				}else
				if(client->options.opengl_mode == GL_MODE_FULL){
					((mc_Vertex**)verts)[k][(*vi)[k]-((*vi)[k]-v0[k])+j].anim_mode += 10.0 * mode;
				}
			}
		}
	}
}

void BlockRender::GenerateSpriteVolume(float height, bool north, bool south, bool east, bool west, bool up, bool down, u8* verts[6], int** vi, float x, float y, float z){
	int j;
	int biome_color = 0;
	
	float tu = mat->renderProps.u;
	float tv = mat->renderProps.v;
	float tw = mat->renderProps.w;
	float th = mat->renderProps.h;
	
	biome_color = mat->isBiomeColored() & 0x000001;
	MakeVertex(verts[NORTH] + client->options.vertex_size * ((*vi)[NORTH]+0), NORTH, biome_color, 255, x+0.0, y+0.0, z+0.0, tu, tv+th, -1.0, 0.0, 0.0);
	MakeVertex(verts[NORTH] + client->options.vertex_size * ((*vi)[NORTH]+1), NORTH, biome_color, 255, x+1.0, y+1.0, z+0.0, tu+tw, tv+th, -1.0, 0.0, 0.0);
	MakeVertex(verts[NORTH] + client->options.vertex_size * ((*vi)[NORTH]+2), NORTH, biome_color, 255, x+1.0, y+1.0, z+height, tu+tw, tv, -1.0, 0.0, 0.0);
	MakeVertex(verts[NORTH] + client->options.vertex_size * ((*vi)[NORTH]+3), NORTH, biome_color, 255, x+1.0, y+1.0, z+height, tu+tw, tv, -1.0, 0.0, 0.0);
	MakeVertex(verts[NORTH] + client->options.vertex_size * ((*vi)[NORTH]+4), NORTH, biome_color, 255, x+0.0, y+0.0, z+height, tu, tv, -1.0, 0.0, 0.0);
	MakeVertex(verts[NORTH] + client->options.vertex_size * ((*vi)[NORTH]+5), NORTH, biome_color, 255, x+0.0, y+0.0, z+0.0, tu, tv+th, -1.0, 0.0, 0.0);
	(*vi)[NORTH] += 6;
	biome_color = mat->isBiomeColored() & 0x000010;
	MakeVertex(verts[SOUTH] + client->options.vertex_size * ((*vi)[SOUTH]+0), SOUTH, biome_color, 255, x+0.0, y+0.0, z+0.0, tu, tv+th, -1.0, 0.0, 0.0);
	MakeVertex(verts[SOUTH] + client->options.vertex_size * ((*vi)[SOUTH]+1), SOUTH, biome_color, 255, x+1.0, y+1.0, z+height, tu+tw, tv, -1.0, 0.0, 0.0);
	MakeVertex(verts[SOUTH] + client->options.vertex_size * ((*vi)[SOUTH]+2), SOUTH, biome_color, 255, x+1.0, y+1.0, z+0.0, tu+tw, tv+th, -1.0, 0.0, 0.0);
	MakeVertex(verts[SOUTH] + client->options.vertex_size * ((*vi)[SOUTH]+3), SOUTH, biome_color, 255, x+1.0, y+1.0, z+height, tu+tw, tv, -1.0, 0.0, 0.0);
	MakeVertex(verts[SOUTH] + client->options.vertex_size * ((*vi)[SOUTH]+4), SOUTH, biome_color, 255, x+0.0, y+0.0, z+0.0, tu, tv+th, -1.0, 0.0, 0.0);
	MakeVertex(verts[SOUTH] + client->options.vertex_size * ((*vi)[SOUTH]+5), SOUTH, biome_color, 255, x+0.0, y+0.0, z+height, tu, tv, -1.0, 0.0, 0.0);
	(*vi)[SOUTH] += 6;
	biome_color = mat->isBiomeColored() & 0x000100;
	MakeVertex(verts[EAST] + client->options.vertex_size * ((*vi)[EAST]+0), EAST, biome_color, 255, x+0.0, y+1.0, z+0.0, tu, tv+th, -1.0, 0.0, 0.0);
	MakeVertex(verts[EAST] + client->options.vertex_size * ((*vi)[EAST]+1), EAST, biome_color, 255, x+1.0, y+0.0, z+0.0, tu+tw, tv+th, -1.0, 0.0, 0.0);
	MakeVertex(verts[EAST] + client->options.vertex_size * ((*vi)[EAST]+2), EAST, biome_color, 255, x+1.0, y+0.0, z+height, tu+tw, tv, -1.0, 0.0, 0.0);
	MakeVertex(verts[EAST] + client->options.vertex_size * ((*vi)[EAST]+3), EAST, biome_color, 255, x+1.0, y+0.0, z+height, tu+tw, tv, -1.0, 0.0, 0.0);
	MakeVertex(verts[EAST] + client->options.vertex_size * ((*vi)[EAST]+4), EAST, biome_color, 255, x+0.0, y+1.0, z+height, tu, tv, -1.0, 0.0, 0.0);
	MakeVertex(verts[EAST] + client->options.vertex_size * ((*vi)[EAST]+5), EAST, biome_color, 255, x+0.0, y+1.0, z+0.0, tu, tv+th, -1.0, 0.0, 0.0);
	(*vi)[EAST] += 6;
	biome_color = mat->isBiomeColored() & 0x001000;
	MakeVertex(verts[WEST] + client->options.vertex_size * ((*vi)[WEST]+0), WEST, biome_color, 255, x+0.0, y+1.0, z+0.0, tu, tv+th, -1.0, 0.0, 0.0);
	MakeVertex(verts[WEST] + client->options.vertex_size * ((*vi)[WEST]+1), WEST, biome_color, 255, x+1.0, y+0.0, z+height, tu+tw, tv, -1.0, 0.0, 0.0);
	MakeVertex(verts[WEST] + client->options.vertex_size * ((*vi)[WEST]+2), WEST, biome_color, 255, x+1.0, y+0.0, z+0.0, tu+tw, tv+th, -1.0, 0.0, 0.0);
	MakeVertex(verts[WEST] + client->options.vertex_size * ((*vi)[WEST]+3), WEST, biome_color, 255, x+1.0, y+0.0, z+height, tu+tw, tv, -1.0, 0.0, 0.0);
	MakeVertex(verts[WEST] + client->options.vertex_size * ((*vi)[WEST]+4), WEST, biome_color, 255, x+0.0, y+1.0, z+0.0, tu, tv+th, -1.0, 0.0, 0.0);
	MakeVertex(verts[WEST] + client->options.vertex_size * ((*vi)[WEST]+5), WEST, biome_color, 255, x+0.0, y+1.0, z+height, tu, tv, -1.0, 0.0, 0.0);
	(*vi)[WEST] += 6;
	for(int k=0; k<4; k++){
		for(j=0; j<6; j++){
			if(client->options.opengl_mode == GL_MODE_FAST){
				// No physic animation
			}else
			if(client->options.opengl_mode == GL_MODE_BASIC && ((mc_Vertex_Basic**)verts)[k][(*vi)[k]-6+j].z == z+1.0){
				((mc_Vertex_Basic**)verts)[k][(*vi)[k]-6+j].anim_mode += 10.0 * 1;
			}else
			if(client->options.opengl_mode == GL_MODE_FULL && ((mc_Vertex**)verts)[k][(*vi)[k]-6+j].z == z+1.0){
				((mc_Vertex**)verts)[k][(*vi)[k]-6+j].anim_mode += 10.0 * 1;
			}
		}
	}
}

void BlockRender::GenerateFromObject(ge_Object* obj, float height, bool north, bool south, bool east, bool west, bool up, bool down, u8* verts[6], int** vi, float x, float y, float z){
	int v = 0;
	int i, j, k;
	
	int v0[6];
	v0[0] = (*vi)[0];
	v0[1] = (*vi)[1];
	v0[2] = (*vi)[2];
	v0[3] = (*vi)[3];
	v0[4] = (*vi)[4];
	v0[5] = (*vi)[5];

	float tu = mat->renderProps.u;
	float tv = mat->renderProps.v;
	float tw = mat->renderProps.w;
	float th = mat->renderProps.h;

	v = obj->nVerts;
	for(i=0; i<v; i++){
		float normal[3] = { obj->verts[i].nx, obj->verts[i].ny, obj->verts[i].nz };
		geNormalize(normal);
		j = UP;
		if(normal[0] == 0.0 && normal[1] == 0.0 && normal[2] == -1.0){
			j = DOWN;
		}
		if(normal[0] == 1.0 && normal[1] == 0.0 && normal[2] == 0.0){
			j = NORTH;
		}
		if(normal[0] == -1.0 && normal[1] == 0.0 && normal[2] == 0.0){
			j = SOUTH;
		}
		if(normal[0] == 0.0 && normal[1] == 1.0 && normal[2] == 0.0){
			j = EAST;
		}
		if(normal[0] == 0.0 && normal[1] == -1.0 && normal[2] == 0.0){
			j = WEST;
		}
		if(client->options.opengl_mode == GL_MODE_FAST){
			((mc_Vertex_Fast**)verts)[j][(*vi)[j]].x = obj->verts[i].x * 128.0;
			((mc_Vertex_Fast**)verts)[j][(*vi)[j]].y = obj->verts[i].y * 128.0;
			((mc_Vertex_Fast**)verts)[j][(*vi)[j]].z = obj->verts[i].z * 128.0;
			((mc_Vertex_Fast**)verts)[j][(*vi)[j]].u = obj->verts[i].u * 32767.0;
			((mc_Vertex_Fast**)verts)[j][(*vi)[j]].v = -obj->verts[i].v * 32767.0;
			((mc_Vertex_Fast**)verts)[j][(*vi)[j]].color[0] = 255;
			((mc_Vertex_Fast**)verts)[j][(*vi)[j]].color[1] = 255;
			((mc_Vertex_Fast**)verts)[j][(*vi)[j]].color[2] = 255;
			((mc_Vertex_Fast**)verts)[j][(*vi)[j]].color[3] = 255;
		}else
		if(client->options.opengl_mode == GL_MODE_BASIC){
			((mc_Vertex_Basic**)verts)[j][(*vi)[j]].nx = 127.0 * normal[0];
			((mc_Vertex_Basic**)verts)[j][(*vi)[j]].ny = 127.0 * normal[1];
			((mc_Vertex_Basic**)verts)[j][(*vi)[j]].nz = 127.0 * normal[2];
			((mc_Vertex_Basic**)verts)[j][(*vi)[j]].x = obj->verts[i].x;
			((mc_Vertex_Basic**)verts)[j][(*vi)[j]].y = obj->verts[i].y;
			((mc_Vertex_Basic**)verts)[j][(*vi)[j]].z = obj->verts[i].z;
			((mc_Vertex_Basic**)verts)[j][(*vi)[j]].u = obj->verts[i].u;
			((mc_Vertex_Basic**)verts)[j][(*vi)[j]].v = -obj->verts[i].v;
			((mc_Vertex_Basic**)verts)[j][(*vi)[j]].color[0] = 255;
			((mc_Vertex_Basic**)verts)[j][(*vi)[j]].color[1] = 255;
			((mc_Vertex_Basic**)verts)[j][(*vi)[j]].color[2] = 255;
			((mc_Vertex_Basic**)verts)[j][(*vi)[j]].color[3] = 255;
		}else
		if(client->options.opengl_mode == GL_MODE_FULL){
			((mc_Vertex**)verts)[j][(*vi)[j]].nx = 127.0 * normal[0];
			((mc_Vertex**)verts)[j][(*vi)[j]].ny = 127.0 * normal[1];
			((mc_Vertex**)verts)[j][(*vi)[j]].nz = 127.0 * normal[2];
			((mc_Vertex**)verts)[j][(*vi)[j]].x = obj->verts[i].x;
			((mc_Vertex**)verts)[j][(*vi)[j]].y = obj->verts[i].y;
			((mc_Vertex**)verts)[j][(*vi)[j]].z = obj->verts[i].z;
			((mc_Vertex**)verts)[j][(*vi)[j]].u = obj->verts[i].u;
			((mc_Vertex**)verts)[j][(*vi)[j]].v = obj->verts[i].v;
			((mc_Vertex**)verts)[j][(*vi)[j]].color[0] = 255; //block->light; // illumination
			((mc_Vertex**)verts)[j][(*vi)[j]].color[1] = (u8)(255.0 * mat->renderProps.specular); // specular
			((mc_Vertex**)verts)[j][(*vi)[j]].color[2] = 0; // biome_colored
			((mc_Vertex**)verts)[j][(*vi)[j]].color[3] = 0; // unused
		}
		(*vi)[j]++;
	}

	
	for(k=0; k<6; k++){
		for(j=0; j<((*vi)[k]-v0[k]); j++){
			int rot = 0;
			if(mat->renderProps.blockType == 6){
				if((mat->getData() & 3) == 3){
					rot = 3;
				}else
				if((mat->getData() & 2) == 2){
					rot = 2;
				}else
				if((mat->getData() & 1) == 1){
					rot = 1;
				}
			}else
			if(mat->renderProps.blockType == 8){
				if((block->getData() & 1) == 0){
					rot = 2;
				}
			}
			if(client->options.opengl_mode == GL_MODE_FAST){
				mc_Vertex_Fast* v = &((mc_Vertex_Fast**)verts)[k][(*vi)[k]-((*vi)[k]-v0[k])+j];
				float vx = ((float)((mc_Vertex_Fast*)v)->x) / 128.0;
				float vy = ((float)((mc_Vertex_Fast*)v)->y) / 128.0;
				float vz = ((float)((mc_Vertex_Fast*)v)->z) / 128.0;
				if(rot == 3){
					float vx2 = vx * geCos(M_PI / 2.0) - vy * geSin(M_PI / 2.0) + 1.0;
					float vy2 = vx * geSin(M_PI / 2.0) + vy * geCos(M_PI / 2.0);
					vx = vx2;
					vy = vy2;
				}else
				if(rot == 2){
					//float vx2 = vx * geCos(-M_PI / 2.0) - vy * geSin(-M_PI / 2.0);
					//float vy2 = vx * geSin(-M_PI / 2.0) + vy * geCos(-M_PI / 2.0) + 1.0;
					float vx2 = vx * 0.0 - vy * -1.0;
					float vy2 = vx * -1.0 + vy * 0.0 + 1.0;
					vx = vx2;
					vy = vy2;
				}else
				if(rot == 1){
					float vx2 = vx * geCos(M_PI) - vy * geSin(M_PI) + 1.0;
					float vy2 = vx * geSin(M_PI) + vy * geCos(M_PI) + 1.0;
					vx = vx2;
					vy = vy2;
				}
				((mc_Vertex_Fast*)v)->x = (vx + x) * 128.0;
				((mc_Vertex_Fast*)v)->y = (vy + y) * 128.0;
				((mc_Vertex_Fast*)v)->z = (vz + z) * 128.0;
				((mc_Vertex_Fast*)v)->u = ((((float)((mc_Vertex_Fast*)v)->u) / 32767.0) * tw + tu) * 32768.0;
				((mc_Vertex_Fast*)v)->v = ((((float)((mc_Vertex_Fast*)v)->v) / 32767.0) * th + tv) * 32768.0;
				((mc_Vertex_Fast*)v)->anim = 256 * mat->renderProps.animations + (short)floor(mat->renderProps.h * 256.0);
				((mc_Vertex_Fast*)v)->x += (block->getLight() * 15 / 256) * 4096;
			}else
			if(client->options.opengl_mode == GL_MODE_BASIC){
				mc_Vertex_Basic* v = &((mc_Vertex_Basic**)verts)[k][(*vi)[k]-((*vi)[k]-v0[k])+j];
				float vx = ((mc_Vertex_Basic*)v)->x;
				float vy = ((mc_Vertex_Basic*)v)->y;
				if(rot == 3){
					((mc_Vertex_Basic*)v)->x = vx * geCos(M_PI / 2.0) - vy * geSin(M_PI / 2.0) + 1.0;
					((mc_Vertex_Basic*)v)->y = vx * geSin(M_PI / 2.0) + vy * geCos(M_PI / 2.0);
				}else
				if(rot == 2){
					((mc_Vertex_Basic*)v)->x = vx * geCos(-M_PI / 2.0) - vy * geSin(-M_PI / 2.0);
					((mc_Vertex_Basic*)v)->y = vx * geSin(-M_PI / 2.0) + vy * geCos(-M_PI / 2.0) + 1.0;
				}else
				if(rot == 1){
					((mc_Vertex_Basic*)v)->x = vx * geCos(M_PI) - vy * geSin(M_PI) + 1.0;
					((mc_Vertex_Basic*)v)->y = vx * geSin(M_PI) + vy * geCos(M_PI) + 1.0;
				}
				((mc_Vertex_Basic*)v)->x += x;
				((mc_Vertex_Basic*)v)->y += y;
				((mc_Vertex_Basic*)v)->z += z;
				((mc_Vertex_Basic*)v)->u = ((mc_Vertex_Basic*)v)->u * tw + tu;
				((mc_Vertex_Basic*)v)->v = ((mc_Vertex_Basic*)v)->v * th + tv;
				((mc_Vertex_Basic*)v)->anim_mode = 100.0 * mat->renderProps.animations + mat->renderProps.h;
				float f_light = fmax(1.0, floor(100.0 * (((float)block->getLight()) / 256.0)));
				((mc_Vertex_Basic*)v)->x += f_light * 1000.0;
			}else
			if(client->options.opengl_mode == GL_MODE_FULL){
				mc_Vertex* v = &((mc_Vertex**)verts)[k][(*vi)[k]-((*vi)[k]-v0[k])+j];
				float vx = ((mc_Vertex*)v)->x;
				float vy = ((mc_Vertex*)v)->y;
				if(rot == 3){
					((mc_Vertex*)v)->x = vx * geCos(M_PI / 2.0) - vy * geSin(M_PI / 2.0) + 1.0;
					((mc_Vertex*)v)->y = vx * geSin(M_PI / 2.0) + vy * geCos(M_PI / 2.0);
				}else
				if(rot == 2){
					//((mc_Vertex*)v)->x = vx * geCos(-M_PI / 2.0) - vy * geSin(-M_PI / 2.0);
					//((mc_Vertex*)v)->y = vx * geSin(-M_PI / 2.0) + vy * geCos(-M_PI / 2.0) + 1.0;
					((mc_Vertex*)v)->x = vx * 0.0 - vy * 0.5;
					((mc_Vertex*)v)->y = vx * -0.5 + vy * 0.0 + 1.0;
				}else
				if(rot == 1){
					((mc_Vertex*)v)->x = vx * geCos(M_PI) - vy * geSin(M_PI) + 1.0;
					((mc_Vertex*)v)->y = vx * geSin(M_PI) + vy * geCos(M_PI) + 1.0;
				}
				((mc_Vertex*)v)->x += x;
				((mc_Vertex*)v)->y += y;
				((mc_Vertex*)v)->z += z;
				((mc_Vertex*)v)->u = ((mc_Vertex*)v)->u * tw + tu;
				((mc_Vertex*)v)->v = ((mc_Vertex*)v)->v * th + tv;
				((mc_Vertex*)v)->anim_mode = 0;
				((mc_Vertex*)v)->color[3] = 0.0;
			}
		}
	}
}

void BlockRender::GenerateStairs(float height, bool north, bool south, bool east, bool west, bool up, bool down, u8* verts[6], int** vi, float x, float y, float z){
	GenerateFromObject(client->res.stairs, height, north, south, east, west, up, down, verts, vi, x, y, z);
}

void BlockRender::GenerateRail(float height, bool north, bool south, bool east, bool west, bool up, bool down, u8* verts[6], int** vi, float x, float y, float z){
	GenerateFromObject(client->res.rail, height, north, south, east, west, up, down, verts, vi, x, y, z);
}

void BlockRender::FancyGrass(Block* block, float* tu, float *tv, int* biome_color, int xincr, int yincr){
	return;
/*
	Block* b = ChunkFindBlock(&GetWorld()->chunks[block->chunk_id], block->x + xincr, block->y + yincr, block->z);
	if(b && GetBlockProps(b->id, b->ext) && GetBlockProps(b->id, b->ext)->solid == 0){
		b = ChunkFindBlock(&GetWorld()->chunks[block->chunk_id], b->x, b->y, b->z - 1);
		if(b && b->id == 2){
			*tu = 0.0 / 16.0;
			*tv = 0.0 / 16.0;
			*biome_color = true;
		}
	}
*/
}

void BlockRender::MakeVertex(void* _vert, int face, int biome_colored, u8 light, float x, float y, float z, float tx, float ty, float nx, float ny, float nz){
	light = 255;
	if(client->options.opengl_mode == GL_MODE_FAST){
		mc_Vertex_Fast* vert = (mc_Vertex_Fast*)_vert;

		vert->color[0] = light;
		vert->color[1] = light;
		vert->color[2] = light;
		vert->color[3] = 255;
		if(biome_colored){
			vert->color[0] = 102 * light / 255;
			vert->color[1] = 204 * light / 255;
			vert->color[2] = 76 * light / 255;
		}
		
		vert->x = (short)(x * 128.0);
		vert->y = (short)(y * 128.0);
		vert->z = (short)(z * 128.0);
		
		vert->u = (short)(tx * 32768.0);
		vert->v = (short)(ty * 32768.0);

		vert->anim = 256 * mat->renderProps.animations + (short)floor(mat->renderProps.h * 256.0);
		vert->x += (block->getLight() * 15 / 256) * 4096;
	}
	else
	if(client->options.opengl_mode == GL_MODE_BASIC){
		mc_Vertex_Basic* vert = (mc_Vertex_Basic*)_vert;

		vert->color[0] = light;
		vert->color[1] = light;
		vert->color[2] = light;
		vert->color[3] = 255;
		if(biome_colored){
			vert->color[0] = 102 * light / 255;
			vert->color[1] = 204 * light / 255;
			vert->color[2] = 76 * light / 255;
		}

		vert->x = x;
		vert->y = y;
		vert->z = z;
	
		vert->u = tx;
		vert->v = ty;

		float f_light = fmax(1.0, floor(100.0 * (((float)block->getLight()) / 256.0)));
		vert->anim_mode = 100.0 * mat->renderProps.animations + mat->renderProps.h;
		vert->x += f_light * 1000.0;
	
		float normal[3] = { nx, ny, nz };
		geNormalize(normal);
		vert->nx = 127.0 * normal[0];
		vert->ny = 127.0 * normal[1];
		vert->nz = 127.0 * normal[2];
	}
	else
	if(client->options.opengl_mode == GL_MODE_FULL){
		mc_Vertex* vert = (mc_Vertex*)_vert;
	}
}
